package game;

import java.io.ByteArrayOutputStream;

public class Base64 {
	// 変換表
	private static final String[] base64table = {
		 "A", "B", "C", "D", "E", "F", "G", "H",
		 "I", "J", "K", "L", "M", "N", "O", "P",
		 "Q", "R", "S", "T", "U", "V", "W", "X",
		 "Y", "Z", "a", "b", "c", "d", "e", "f",
		 "g", "h", "i", "j", "k", "l", "m", "n",
		 "o", "p", "q", "r", "s", "t", "u", "v",
		 "w", "x", "y", "z", "0", "1", "2", "3",
		 "4", "5", "6", "7", "8", "9", "+", "/"
	};

	/**
	 * バイト配列をBASE64エンコードします。
	 * @param bytes エンコード対象のバイト配列
	 * @return エンコード後の文字列
	 */
	public static String encode( byte[] bytes ) {

		// バイト配列をビットパターンに変換します。
		StringBuffer bitPattern = new StringBuffer();
		for ( int i = 0; i < bytes.length; ++i ) {
			int b = bytes[i];
			if ( b < 0 ) {
				b += 256;
			}
			String tmp = Integer.toBinaryString( b );
			while ( tmp.length() < 8 ) {
				tmp = "0" + tmp;
			}
			bitPattern.append( tmp );
		}

		// ビットパターンのビット数が6の倍数にするため、末尾に0を追加します。
		while ( bitPattern.length() % 6 != 0 ) {
			bitPattern.append( "0" );
		}

		// 変換表を利用して、ビットパターンを4ビットずつ文字に変換します。
		StringBuffer encoded = new StringBuffer();
		for ( int i = 0; i < bitPattern.length(); i += 6 ) {
			String tmp = bitPattern.substring( i, i + 6 );
			int index = Integer.parseInt( tmp, 2 );
			encoded.append( base64table[index] );
		}

		// 変換後の文字数を4の倍数にするため、末尾に=を追加します。
		while ( encoded.length() % 4 != 0 ) {
			encoded.append( "=" );
		}

		return encoded.toString();
	}

	/**
	 * 文字列をBASE64デコードします。
	 *
	 * @param str
	 *            デコード対象の文字列
	 * @return デコード後のバイト配列
	 */
	public static byte[] decode(String str) {

		StringBuffer bitPattern = new StringBuffer();
		for (char c : str.toCharArray()) {
			int code = -1;
			String letter = Character.toString(c);
			for (int i = 0; i < base64table.length; i++) {
				if (base64table[i].equals(letter)) {
					code = i;
					break;
				}
			}
			if (code >= 0) {
				String tmp = Integer.toBinaryString(code);
				while (tmp.length() < 6) {
					tmp = "0" + tmp;
				}
				bitPattern.append(tmp);
			}
		}

		ByteArrayOutputStream decoded = new ByteArrayOutputStream();
		for (int i = 0; i + 7 < bitPattern.length(); i+=8) {
			String tmp = bitPattern.substring(i, i + 8);
			decoded.write(Integer.parseInt(tmp, 2));
		}

		return decoded.toByteArray();
	}

}
